﻿using System;
using System.Threading;

namespace CommonEngine.Tools
{
    /// <summary>
    /// 自定义的队列---先进先出---线程安全
    /// </summary>
    public class AppQueue<T>
    {
        private class Node<K>
        {
            internal K Item;
            internal Node<K> Next;
            public Node(K item, Node<K> next)
            {
                this.Item = item;
                this.Next = next;
            }
        }

        private Node<T> _head;
        private Node<T> _tail;

        public AppQueue()
        {
            this._head = new Node<T>(default(T), null);
            this._tail = this._head;
        }

        public bool IsEmpty
        {
            get { return (this._head.Next == null); }
        }

        public void Enqueue(T item)
        {
            Node<T> newNode = new Node<T>(item, null);
            while (true)
            {
                Node<T> curTail = _tail;
                Node<T> residue = curTail.Next;

                if (curTail == _tail)
                {
                    if (residue == null)
                    {
                        if (Interlocked.CompareExchange<Node<T>>(ref curTail.Next, newNode, residue) == residue)
                        {
                            Interlocked.CompareExchange<Node<T>>(ref _tail, newNode, curTail);
                            return;
                        }
                    }
                    else
                    {
                        Interlocked.CompareExchange<Node<T>>(ref _tail, residue, curTail);
                    }
                }
            }
        }

        //出队列
        public bool TryDequeue(out T result)
        {
            Node<T> curHead;
            Node<T> curTail;
            Node<T> next;
            do
            {
                curHead = _head;
                curTail = _tail;
                next = curHead.Next;
                if (curHead == _head)
                {
                    if (next == null)
                    {
                        result = default(T);
                        return false;
                    }
                    if (curHead == curTail)
                    {
                        Interlocked.CompareExchange<Node<T>>(ref _tail, next, curTail);
                    }
                    else
                    {
                        result = next.Item;
                        if (Interlocked.CompareExchange<Node<T>>(ref _head, next, curHead) == curHead)
                            break;
                    }
                }
            }
            while (true);
            return true;
        }

        public T Dequeue()
        {
            T result = default(T);
            if (this.TryDequeue(out result))
                return result;
            else
            {
                if (typeof(T) == typeof(DateTime))
                    return (T)((object)DateTime.Now);
                else
                    return default(T);
            }
        }
    }
}
